﻿#region using
/*
 * Created by SharpDevelop.
 * User: Andrew
 * Date: 22/04/2013
 * Time: 22:13
 * 
 * To change this template use Tools | Options | Coding | Edit Standard Headers.
 */
using System;
using System.Collections.Generic;
using System.Drawing;
using System.Linq;

using RRRSRoguelike.Entities;
using RRRSRoguelike.Entities.Creatures;
using RRRSRoguelike.Entities.Props;
using RRRSRoguelike.Enums;
using RRRSRoguelike.Helpers;
using RRRSRoguelike.Helpers.Actions;
using RRRSRoguelike.Managers;
using RRRSRoguelike.Screens;
#endregion

namespace RRRSRoguelike.RuleSets
{
	/// <summary>
	/// The full feature set of the Ancient Blade release
	/// </summary>
	public class AncientBlade:RuleSet
	{

		public AncientBlade():base()
		{
		}
		
		public override void Initialize()
		{
			base.Initialize();
			
			AddStats();
			

			
		}

		protected override void AddFlags()
		{
			// specific to jump ability
			player.Flags.Add("hasJumped", false);
			//specific to the fireball
			player.Flags.Add("hasFired", false);
		}

		protected override void ResetBools()
		{
			player.Flags["hasJumped"] = false;
			player.Flags["hasFired"] = false;
		}
		
		void AddStats()
		{
			//Add Stats
			player.Stats.StatList.Add("MonstersKilled", 0);
			player.Stats.StatList.Add("StepsTaken", 0);
			player.Stats.StatList.Add("WeaponsGrabbed", 0);
		}
		
		public override void DoLogic()
		{
				
			// specific to fireball
			var fireball = GameManager.Instance.PropManager.Fireball;
			if (fireball.Active)
				ProcessFireball(fireball);
			
			base.DoLogic();

		}
		
		//FIXME: belongs in fireballruleset
		private static void ProcessFireball(Entities.Props.Fireball fireball)
		{
			//FIXME: this should be more generic to allow all kinds of ranged weapons
			long lastmove = 0;
			long delay = 120;
			while (fireball.Active && GameManager.Instance.DungeonLevel.IsOKToMove(fireball.Position))
			{
				if (ApplicationManager.Instance.Time.ElapsedMilliseconds > lastmove + delay)
				{
					lastmove = ApplicationManager.Instance.Time.ElapsedMilliseconds;

					fireball.range--;
					//Do fireball stuff
					//GameManager.Instance.PropManager.Fireball
					//Fireball move
					GameManager.Instance.PropManager.Fireball.Move(fireball.Position, fireball.Direction, 1);
					//Fireball kill monsters
					List<Monster> monstersInBattle =
						GameManager.Instance.CreatureManager.Monsters.Where(m => m.X == fireball.X && m.Y == fireball.Y).ToList();
					
					foreach (var monster in monstersInBattle)
					{
						fireball.Kill(monster);

						GameManager.Instance.PlaySound(SoundList.Battle);

						fireball.ImageCharacter = "*";

						GameManager.Instance.DungeonVisualizer.Flash(fireball);

						fireball.ImageCharacter = "o";
						fireball.Color = ConsoleColor.Magenta;
						fireball.Active = false;
					}
					if (fireball.range == 0)
						fireball.Active = false;

					//Draw
					GameManager.Instance.ForceRedraw();

				}
			}
			GameManager.Instance.PropManager.Fireball.Active = false;
			GameManager.Instance.Redraw = true;
		}
		
		
		protected override void CheckNewTile()
		{
			//FIXME: things here should be more event driven
			
			base.CheckNewTile();
			
			var newPosition = new Point(player.X, player.Y);
			// Should add options for auto moves
			//auto pick up sword
			if (player.WeaponSlot == null)
				ActionHelper.Get(newPosition);

			// auto take stairwell
			TakeStairWell(newPosition);
		}
		
		public override void LoadContent()
		{
			//Get Data from file
			GameManager.Instance.Dungeon.LoadData("Vanilla.xml");
			
			base.LoadContent();
		}
		
		public override void ProcessInput()
		{
			var ActionManager = GameManager.Instance.ActionManager;

			processMonsters = player.Flags["hasMoved"] = GameManager.Instance.Redraw = true;

			//FIXME: we need something better than this giant load of if statements
			
			for (int i = 0; i < ActionManager.ActionMap.Count();i++)
			{
				if(ActionManager.IsActionPushed((Actions)i))
				   {
						if ((ActionManager.ActionMap[i].ActionEvent != null)) 
						{
							ActionManager.ActionMap[i].ActionEvent.Invoke(this, new EventArgs());
						}
						//HACK: use return to exit method altogether
						//return;
						//this ends the for loop
						break;
				   }
			}
			
			//This checks until one is true as we can only have one action press.
			if (ActionManager.IsActionPushed(Actions.North))
				player.Flags["hasMoved"] = processMonsters = MovePlayer(Direction.N);
			else if (ActionManager.IsActionPushed(Actions.South))
				player.Flags["hasMoved"] = processMonsters = MovePlayer(Direction.S);
			else if (ActionManager.IsActionPushed(Actions.East))
				player.Flags["hasMoved"] = processMonsters = MovePlayer(Direction.E);
			else if (ActionManager.IsActionPushed(Actions.West))
				player.Flags["hasMoved"] = processMonsters = MovePlayer(Direction.W);
			else if (ActionManager.IsActionPushed(Actions.Jump))
			{
				DoJump();
			}
			else if (ActionManager.IsActionPushed(Actions.Shoot))
			{
				ShootFireball();
			}
			else if (ActionManager.IsActionPushed(Actions.Pick))
			{
				ActionHelper.Get(player.Position);
				processMonsters = player.Flags["hasMoved"] = false;
			}
			else if (ActionManager.IsActionPushed(Actions.Drop))
			{
				ActionHelper.Put(player.Position);
				processMonsters = player.Flags["hasMoved"] = false;
			}
			else if (ActionManager.IsActionPushed(Actions.Look))
			{
				DoLook();
				processMonsters = player.Flags["hasMoved"] = false;
			}
			else if (ActionManager.IsActionPushed(Actions.Build))
			{
				if(player.WeaponSlot !=null && player.WeaponSlot.Name == "Hammer")
				{
					dungeonScreen.DoBuildMenu();
				}
				else
				{
					//FIXME: this should be a localized string
					dungeonScreen.ShowMessage("You need a hammer!");
					processMonsters = player.Flags["hasMoved"] = false;
				}



				GameManager.Instance.Redraw = true;
			}
			else if (ActionManager.IsActionPushed(Actions.Trap))
			{
				if(player.WeaponSlot !=null)
				{
					DoTrap();}
				else
				{
					//FIXME: make a localized string
					dungeonScreen.ShowMessage("You need a weapon!");
					processMonsters = player.Flags["hasMoved"] = false;
				}
				GameManager.Instance.Redraw = true;
			}
			else if (ActionManager.IsActionPushed(Actions.Open))
			{
				DoOpen();
				GameManager.Instance.Redraw = true;
			}
			else if (ActionManager.IsActionPushed(Actions.Wait))
			{
				player.Flags["hasMoved"] = false;
			}
			else if (ActionManager.IsActionPushed(Actions.Quit))
			{
				dungeonScreen.ShowQuitScreen();
				processMonsters = player.Flags["hasMoved"] = false;
			}
			else if (ActionManager.IsActionPushed(Actions.Help))
			{
				dungeonScreen.ShowHelpScreen();
				processMonsters = player.Flags["hasMoved"] = false;
			}
			else if (ActionManager.IsActionPushed(Actions.FollowToggle))
			{
				Properties.Settings.Default.FollowToggle =
					ApplicationManager.Instance.ToggleSetting(Properties.Settings.Default.FollowToggle);

				processMonsters = player.Flags["hasMoved"] = false;
			}
			else if (ActionManager.IsActionPushed(Actions.SoundToggle))
			{
				//Toggle sound
				Properties.Settings.Default.SoundToggle =
					ApplicationManager.Instance.ToggleSetting(Properties.Settings.Default.SoundToggle);

				Properties.Settings.Default.Save();

				ApplicationManager.Instance.SoundManager.PlaySound(SoundList.Pluck.ToString());

				processMonsters = player.Flags["hasMoved"] = false;
			}
			else if (ActionManager.IsActionPushed(Actions.ToggleGodMode))
			{
				//Toggle godmode
				GameManager.Instance.GodMode =
					ApplicationManager.Instance.ToggleSetting(GameManager.Instance.GodMode);

				processMonsters = player.Flags["hasMoved"] = false;

			}
			else if (ActionManager.IsActionPushed(Actions.ChangeAnimationSpeed))
			{
				ApplicationManager.Instance.ChangeAnimSpeed();

				processMonsters = player.Flags["hasMoved"] = false;
			}
			else
			{
				processMonsters = player.Flags["hasMoved"] = GameManager.Instance.Redraw = false;
			}}
		
		
		private void DoLook()
		{
			bool newTile = false;
			bool look = true;

			Tile lookTile = GameManager.Instance.PropManager.LookTile;

			lookTile.Active = true;
			lookTile.Position = player.Position;

			
			//FIXME Looking could be a game state.  That would move this loop.
			while (look)
			{
				var ActionManager = GameManager.Instance.ActionManager;
				
				dungeonScreen.GetInput();

				if (ActionManager.IsActionPushed(Actions.North))
				{ lookTile.Y -= 1; newTile = true; }
				else if (ActionManager.IsActionPushed(Actions.South))
				{ lookTile.Y += 1; newTile = true; }
				else if (ActionManager.IsActionPushed(Actions.East))
				{ lookTile.X += 1; newTile = true; }
				else if (ActionManager.IsActionPushed(Actions.West))
				{ lookTile.X -= 1; newTile = true; }
				else if (ActionManager.IsActionPushed(Actions.Quit) ||
				         ActionManager.IsActionPushed(Actions.Look))
				{
					look = false;
				}

				if (newTile)
				{
					//limit

					lookTile.Position = DungeonLevel.ClampToDungeon(lookTile.Position);

					var viewTile = (Tile)GameManager.Instance.DungeonLevel.GetTopTile(lookTile.Position);
					lookTile.ImageCharacter = viewTile.ImageCharacter;
					lookTile.Description = viewTile.Description;
					lookTile.Color = ConsoleColor.Blue;
					lookTile.Background = ConsoleColor.DarkCyan;

					var description = Properties.Strings.MysteryObject;

					if (viewTile.Description != null)
						description = viewTile.Description;

					dungeonScreen.ClearMessages();
					dungeonScreen.ShowMessage(description,false);

					GameManager.Instance.ForceRedraw();
					newTile = false;
				}
				//Draw
			}
			lookTile.Active = false;
			GameManager.Instance.ForceRedraw();
		}
		
		//FIXME: belongs in fireball and needs generic ranged attack
		private void ShootFireball()
		{
			ActionManager ActionManager = GameManager.Instance.ActionManager;
			bool shooting = true;

			//Forces update of hud
			//UNDONE:olduses = -1;
			
			if (player.Flags["hasFired"])
			{
				dungeonScreen.ShowMessage(Properties.Strings.Used);
				processMonsters = player.Flags["hasMoved"] = false;
			}
			else
			{
				var direction = dungeonScreen.GetDirectionFromUser();
				if (direction != Direction.Wait && !player.Flags["hasFired"])
				{
					ActionHelper.ShootFireball(player.Position,direction);
					player.Flags["hasFired"] = true;
					shooting = false;
				}
				else if (direction == Direction.Wait)
					processMonsters = player.Flags["hasMoved"] = shooting = false;

			}
		}
				
		private void DoJump()
		{
			//shortens calls.
			var ActionManager = GameManager.Instance.ActionManager;

			//UNDONE:redraw?
			
			if (player.Flags["hasJumped"])
			{
				dungeonScreen.ShowMessage(Properties.Strings.Used);
				
				processMonsters = player.Flags["hasMoved"] = false;
				
			}
			else
			{

				var jump = true;
				while (jump)
				{
					var direction = dungeonScreen.GetDirectionFromUser();
					if (direction != Direction.Wait)
					{
						player.Flags["hasJumped"] = player.Flags["hasMoved"] = processMonsters = player.MovePlayer(direction, Constants.JumpDistance);
						//exits loop
						jump = false;
					}
					else if (ActionManager.IsActionPushed(Actions.Quit) ||
					         ActionManager.IsActionPushed(Actions.Jump))
					{
						processMonsters = player.Flags["hasMoved"] = jump = false;

					}

				}
				
			}
			
		}
		
		// This could probably be done more elegantly with events.
		bool MovePlayer(Direction direction)
		{
			bool moved = player.MovePlayer(direction);
			
			if(!moved)
			{
				//Get new DungeonSquare check for door
				Point newPosition = DungeonLevel.
					GetNewPosition(player.Position, direction, 1);
				if (GameManager.Instance.DungeonLevel.
				    SquareContainsTile(newPosition,typeof(Door)))
				{//Open that door
					GameManager.Instance.DungeonLevel.
						GetTiles(newPosition).OfType<Door>().FirstOrDefault().Open();
					moved = true;
				}
			}
			return moved;
		}
		
		private void MoveToNextLevel()
		{
			player.Flags["hasJumped"] = false;
			player.Flags["hasFired"] = false;

			//no sword on next level. Murha, ha, ha, ha!!!
			//player.Inventory.Clear();
			//sword now has three uses

			GameManager.NextLevel();

			processMonsters = false;
			
			//TODO: Add an event an hook up a redraw
			//ReDraw();
		}
		
		void DoTrap()
		{
			if (GameManager.Instance.DungeonLevel.SquareContainsTile(player.Position,typeof(Trap)))
			{
				var trap = GameManager.Instance.DungeonLevel.GetTiles(player.Position).
					OfType<Trap>().FirstOrDefault();

				if (trap.IsSet)
					trap.Disarm();
				else
					trap.Set();
			}
			else
			{
				GameManager.Instance.PropManager.Add(new Trap(player.Position));
			}
			player.RemoveWeapon();

		}
		
		private void DoOpen()
		{
			//shortens calls.
			var ActionManager = GameManager.Instance.ActionManager;

			var loop = true;
			while (loop)
			{
				var direction = dungeonScreen.GetDirectionFromUser();
				if (direction != Direction.Wait)
				{

					var position = DungeonLevel.GetNewPosition(player.Position, direction, 1);
					var dungeon = GameManager.Instance.DungeonLevel.
						GetTiles(position).OfType<Door>().FirstOrDefault();

					if (dungeon != null)
					{
						dungeon.Open();
						processMonsters = true;
					}

					//exits loop
					loop = false;
				}
				else if (ActionManager.IsActionPushed(Actions.Quit) ||
				         ActionManager.IsActionPushed(Actions.Jump))
				{
					processMonsters = player.Flags["hasMoved"] = loop = false;

				}

			}

		}
		
		private void TakeStairWell(Point newPosition)
		{
			if (GameManager.Instance.DungeonLevel.GetTile(newPosition, Layers.Prop) is Stairwell)
			{
				//check for victory
				if (GameManager.Instance.CurrentDungeonLevel >= 5)
				{
					GameManager.Instance.gameOver = true;
				}
				else
				{
					MoveToNextLevel();
				}
			}
		}
}
}